package com.hk.weixin.security.miniapp;

import cn.binarywang.wx.miniapp.api.WxMaService;
import com.hk.commons.util.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;

import java.util.Objects;

/**
 * 微信小程序 Filter
 *
 * @author kevin
 * @date 2018年2月8日上午11:18:31
 */
@Slf4j
public class WeiXinMiniappAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private static final String CODE_PARAMETER = "code";

    private final WxMaService wxMaService;

    public WeiXinMiniappAuthenticationFilter(WxMaService wxMaService, String defaultFilterProcessesUrl) {
        super(PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, defaultFilterProcessesUrl));
        setAuthenticationDetailsSource(new WeiXinMiniappAuthenticationDetailsSource());
        this.wxMaService = wxMaService;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        var code = request.getParameter(CODE_PARAMETER);
        if (StringUtils.isEmpty(code)) {
            throw new AuthenticationServiceException("code 为空");
        }
        var userService = wxMaService.getUserService();
        try {
            var sessionResult = userService.getSessionInfo(code);
            if (Objects.isNull(sessionResult)) {
                log.warn("微信小程序认证结果为空");
                throw new AuthenticationServiceException("微信认证失败");
            }
            var token = new WeiXinMiniappAuthenticationToken(sessionResult);
            setDetails(request, token);
            return getAuthenticationManager().authenticate(token);
        } catch (WxErrorException e) {
            logger.error(e.getMessage(), e);
            throw new AuthenticationServiceException("微信认证失败");
        }
    }

    private void setDetails(HttpServletRequest request, WeiXinMiniappAuthenticationToken token) {
        token.setDetails(authenticationDetailsSource.buildDetails(request));
    }
}
